//
// Created by EmFi on 2023/5/14.
//

#include <unordered_set>
#include "BPlusTree.h"
#include "SerializableBPlusTree.h"

template <class K, class V>
void testInsert(BPlusTree<K, V> *tree) {
    cout << "--- testInsert() Started ---" << endl;
    tree->insert(1, -1);
    tree->insert(3, -3);
//    tree->insert(20, -20);
//    tree->insert(18, -18);
    tree->insert(5, -5);
    tree->insert(6, -6);
    tree->insert(8, -8);
    tree->insert(4, -4);
    tree->insert(14, -14);
    tree->insert(15, -15);
//    tree->insert(10, -10);
//    tree->insert(8, -8);
//    tree->insert(3, -3);
//    tree->insert(2, -2);
//    tree->insert(15, -15);
//    tree->insert(16, -16);
//    tree->insert(14, -14);
    tree->print();
    cout << "--- testInsert() Finished ---" << endl;
}

template <class K, class V>
void testSequentialInsert(BPlusTree<K, V> *tree, int num) {
    cout << "--- testSequentialInsert(" << num << ") Started ---" << endl;
    for (int i = 1; i <= num; i++) {
        tree->insert(i, -i);
    }
    tree->print();
    cout << "--- testSequentialInsert(" << num << ") Finished ---" << endl;
}

template <class K, class V>
void testRandomInsert(BPlusTree<K, V> *tree, int num) {
    cout << "--- testRandomInsert(" << num << ") Started ---" << endl;
    unordered_set<int> randSet;
    while (randSet.size() < num) {
        randSet.insert(rand() % 1000 + 1);
    }
    for (auto it: randSet) {
        cout << it << " ";
        tree->insert(it, -it);
    }
    cout << endl;
    tree->print();
    cout << "--- testRandomInsert(" << num << ") Finished ---" << endl;
}

template <class K, class V>
void testFind(BPlusTree<K, V> *tree) {
    cout << "--- testFind() Started ---" << endl;
    for (int i = 200; i <= 600; i++) {
        if (tree->find(i)) {
            cout << i << " ";
        }
    }
    cout << endl;
    cout << "--- testFind() Finished ---" << endl;
}

template <class K, class V>
void testFindRange(BPlusTree<K, V> *tree, int start, int end) {
    cout << "--- testFindRange(" << start << ", " << end << ") Started ---" << endl;
    auto list = tree->find(start, end);
    for (auto it : list) {
        cout << it << " ";
    }
    cout << endl;
    cout << "--- testFindRange(" << start << ", " << end << ") Finished ---" << endl;
}

template <class K, class V>
void testUpdate(BPlusTree<K, V> *tree, K key, V val) {
    cout << "--- testUpdate(" << key << ", " << val << ") Started ---" << endl;
    cout << "Before " << tree->find(key) << " ";
    cout << "Status " << tree->update(key, val) << " ";
    cout << "After " << tree->find(key) << endl;
    cout << "--- testUpdate(" << key << ", " << val << ") Finished ---" << endl;
}

template <class K, class V>
void testRemove(BPlusTree<K, V> *tree) {
    cout << "--- testRemove() Started ---" << endl;
    tree->insert(1, -1);
    tree->insert(3, -3);
    tree->insert(5, -5);
    tree->insert(6, -6);
    tree->insert(8, -8);
    tree->insert(4, -4);
    tree->insert(14, -14);
    tree->insert(15, -15);
    tree->insert(22, -22);
    tree->insert(26, -26);
    tree->insert(40, -40);
    tree->insert(43, -43);
    tree->insert(50, -50);
    tree->insert(30, -30);
    tree->remove(5);
    tree->remove(15);
    tree->remove(3);
    tree->remove(1);
    tree->remove(4);
    tree->remove(6);
    tree->print();
    cout << "--- testRemove() Finished ---" << endl;
}

void testTree() {
    auto *tree = new BPlusTree<int, int>(2);

//    testInsert(tree);
//    testSequentialInsert(tree, 15);
//    tree->remove(15);
//    testRandomInsert(tree, 40);

//    testRemove(tree);

//    testFind(tree);
//    testFindRange(tree, 200, 600);
//    testUpdate(tree, 1, 700);
}

void testSerializable() {
    auto *tree = new SerializableBPlusTree<int, int>(2);
    for (int i = 1; i <= 12; i++) {
        tree->insert(i, -i);
    }
    tree->print();
    tree->open("../bpt/1.bpt");
    tree->save();
    tree->read();
    tree->print();
}
